package twoD.IsoPfem.EmbeddedCrackModel;

import inf.jlinalg.IVector;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

import ptolemy.plot.Plot;
import twoD.IsoPfem.Control.IController;
import twoD.IsoPfem.Control.LoadingState;

public class Plot1D extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private JTextField nTf;// = new JTextField("");
	private JTextField nodeTf;// = new JTextField("");
	private JTextField ElementTf;// = new JTextField("");
	private JCheckBox showGridCb = new JCheckBox("Show grid");
	private JCheckBox xCb = new JCheckBox("x");
	private JCheckBox yCb = new JCheckBox("y");
	private JCheckBox zCb = new JCheckBox("z");
	private JRadioButton disRb = new JRadioButton("load-displacement curve");
	private JRadioButton traRb = new JRadioButton("traction-separation curve");

	private Plot plot = new Plot();

	private IController structController;

	public Plot1D(IController structController) {
		setTitle("Plot Demo");
		setLayout(new BorderLayout(5, 5));
		nodeTf = new JTextField("1");
		ElementTf = new JTextField("0");
		nTf = new JTextField("0");
		xCb.setSelected(false);
		yCb.setSelected(true);
		showGridCb.setSelected(true);

		add(createWestPanel(), BorderLayout.WEST);
		add(this.plot, BorderLayout.CENTER);
		add(createSouthPanel(), BorderLayout.SOUTH);

		Toolkit tk = Toolkit.getDefaultToolkit();
		int xSize = ((int) tk.getScreenSize().getWidth());
		int ySize = ((int) tk.getScreenSize().getHeight());
		setSize(xSize - 100, ySize);

		this.structController = structController;
	}

	public void setN(int n) {
		this.nTf.setText(Integer.toString(n));
	}

	private JPanel createWestPanel() {
		JPanel wp = new JPanel(new BorderLayout());
		wp.add(createInfoPanel(), BorderLayout.NORTH);
		wp.add(createSelectionPanel(), BorderLayout.CENTER);
		wp.add(createSettingsPanel(), BorderLayout.SOUTH);
		return wp;
	}

	private JPanel createInfoPanel() {
		JPanel sp = new JPanel(new BorderLayout(5, 5));
		JPanel p1 = new JPanel(new GridLayout(2, 1, 0, 2));
		JPanel p2 = new JPanel(new GridLayout(2, 1, 0, 2));

		p1.add(new JLabel("n = ", JLabel.RIGHT));

		p2.add(this.nTf);

		sp.setBorder(BorderFactory.createTitledBorder("Info"));
		sp.add(p1, BorderLayout.WEST);
		sp.add(p2, BorderLayout.CENTER);
		return sp;
	}

	private JPanel createSelectionPanel() {
		JPanel sp = new JPanel(new BorderLayout(5, 5));
		JPanel p = new JPanel(new GridLayout(2, 1, 0, 2));

		p.add(disRb);
		p.add(traRb);

		sp.setBorder(BorderFactory.createTitledBorder("Diagram"));
		sp.add(p, BorderLayout.CENTER);

		return sp;
	}

	private JPanel createSettingsPanel() {
		JPanel sp = new JPanel(new BorderLayout(5, 5));
		JPanel p1 = new JPanel(new GridLayout(2, 1, 0, 2));
		JPanel p2 = new JPanel(new GridLayout(2, 1, 0, 2));
		JPanel p3 = new JPanel(new GridLayout(7, 1, 0, 2));

		p1.add(new JLabel("node:", JLabel.RIGHT));
		p1.add(new JLabel("element:", JLabel.RIGHT));

		p2.add(this.nodeTf);
		p2.add(this.ElementTf);

		p3.add(this.xCb);
		p3.add(this.yCb);
		p3.add(this.zCb);
		p3.add(this.showGridCb);

		sp.setBorder(BorderFactory.createTitledBorder("Settings"));
		sp.add(p1, BorderLayout.WEST);
		sp.add(p2, BorderLayout.CENTER);
		sp.add(p3, BorderLayout.SOUTH);

		return sp;
	}

	private JPanel createSouthPanel() {
		JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT));
		p.add(createPlotButton());
		p.add(createExitButton());
		return p;
	}

	private JButton createExitButton() {
		JButton b = new JButton("Exit");

		b.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		return b;
	}

	private JButton createPlotButton() {
		JButton b = new JButton("Plot");

		b.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				plot();
			}
		});
		return b;
	}

	private void plot() {
		try {
			this.plot.clear(true);
			this.plot.setGrid(this.showGridCb.isSelected());

			if (disRb.isSelected()) {
				Integer[] nodeIdSet = this.getNodeIdSet();
				Integer[] axisSet = this.getAxisSet();
				this.plot.setXLabel("displacement (minus)");
				this.plot.setYLabel("load");

				for (int i = 0; i < nodeIdSet.length; i++)
					for (int j = 0; j < axisSet.length; j++) {
						int datasetId = i * axisSet.length + j;
						String legend = "u" + nodeIdSet[i]
								+ getAxisName(axisSet[j]);
						this.plot.addLegend(datasetId, legend);
						for (int k = 0; k < structController.getNumberOfState(); k++) {
							// double x = structController.getStructure()
							// .getMesh().getNodes(i).getDisplacement()
							// .get(j);
							int dof = structController.getStructure().getMesh()
									.getNodes(nodeIdSet[i]).getDofNumbers()[axisSet[j]];
							LoadingState currentState = structController
									.getState(k);
							double x = 0;
							if (dof != -1)
								x = -currentState.getU().get(dof);
							double y = currentState.getLambda();
							plot.addPoint(datasetId, x, y, true);
						}
					}
			}
			if (traRb.isSelected()) {
				Integer[] ElementIdSet = this.getElementIdSet();
				this.plot.setXLabel("e/ef");
				this.plot.setYLabel("g/ft");
				CrackStructure S = (CrackStructure) structController
						.getStructure();
				LoadingFunction lF = S.getLoadingFunction();
				for (int i = 0; i < ElementIdSet.length; i++) {
					int datasetId = i;
					String legend = "e" + ElementIdSet[i];
					this.plot.addLegend(datasetId, legend);
					ArrayList<CrackingState> state = S.getElements(
							ElementIdSet[i]).getCrackState();
					for (int j = 0; j < state.size(); j++) {
						IVector e = state.get(j).getCrackOpeningParameters();
						double y = lF.getTractionSeparationLaw().g(e.get(0))
								/ lF.getTractionSeparationLaw()
										.getTensileStrength();
						double x = e.get(0)
								/ lF.getTractionSeparationLaw().getEf();
						plot.addPoint(datasetId, x, y, true);
					}
				}
			}

			this.plot.repaint();
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, e.getMessage());
		}
	}

	private Integer[] getAxisSet() {
		ArrayList<Integer> list = new ArrayList<Integer>();
		if (this.xCb.isSelected())
			list.add(0);
		if (this.yCb.isSelected())
			list.add(1);
		if (this.zCb.isSelected())
			list.add(2);
		Integer[] a = list.toArray(new Integer[list.size()]);
		return a;
	}

	private Integer[] getNodeIdSet() {
		ArrayList<Integer> list = new ArrayList<Integer>();
		String s = this.nodeTf.getText();
		StringTokenizer st = new StringTokenizer(s, ",");
		while (st.hasMoreTokens()) {
			String val = st.nextToken();
			list.add(Integer.parseInt(val));
		}
		Integer[] a = list.toArray(new Integer[list.size()]);
		return a;
	}

	private Integer[] getElementIdSet() {
		ArrayList<Integer> list = new ArrayList<Integer>();
		String s = this.ElementTf.getText();
		StringTokenizer st = new StringTokenizer(s, ",");
		while (st.hasMoreTokens()) {
			String val = st.nextToken();
			list.add(Integer.parseInt(val));
		}
		Integer[] a = list.toArray(new Integer[list.size()]);
		return a;
	}

	private String getAxisName(int axisNumber) {
		return axisNumber == 0 ? "x" : axisNumber == 1 ? "y" : "z";
	}

}
